package cn.lg.soar.common.data.tree;

import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.*;

/**
 * 树形数据（结果数据，有 children）
 * @author luguoxiang
 * @date 2022/6/13
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface ITreeResult<T extends ITreeResult<T>> {

    /**
     * 获取下级
     * @return
     */
    List<T> getChildren();

    /**
     * 设置下级
     * @param children
     */
    void setChildren(List<T> children);

    /**
     * 将list数据转为树形数据
     * @param list 源数据
     * @param parentId 父id
     * @param handler 转换函数
     * @param <ID> id类型
     * @param <S> 源数据类型
     * @param <R> 树形数据类型
     * @return
     */
    static <ID, S extends ITreeSource<ID>, R extends ITreeResult<R>> List<R> valueOf(Collection<S> list, ID parentId, Function<S, R> handler) {
        List<R> rs = new ArrayList<>();
        for (S t : list) {
            if (!Objects.equals(parentId, t.getParentId())) {
                continue;
            }
            R result = handler.apply(t);
            List<R> ts = valueOf(list, t.getId(), handler);
            if (!ts.isEmpty()) {
                result.setChildren(ts);
            }
            rs.add(result);
        }
        return rs;
    }

    /**
     * 遍历
     * @param tree 树形数据集合
     * @param consumer 消费函数
     * @param parent 父数据
     * @param <T>
     */
    static <T extends ITreeResult<T>>void forEach(Collection<T> tree, BiConsumer<T, T> consumer, T parent) {
        if (tree == null) {
            return;
        }
        for (T t : tree) {
            consumer.accept(t, parent);
            forEach(t.getChildren(), consumer, t);
        }
    }

    /**
     * 遍历
     * @param tree 树形数据集合
     * @param consumer 消费函数
     * @param <T>
     */
    static <T extends ITreeResult<T>>void forEach(Collection<T> tree, Consumer<T> consumer) {
        if (tree == null) {
            return;
        }
        for (T t : tree) {
            consumer.accept(t);
            forEach(t.getChildren(), consumer);
        }
    }

    /**
     * 转换
     * @param tree 树形数据
     * @param converter 转换函数
     * @param parent 父数据
     * @param <T>
     * @param <R>
     * @return
     */
    static <T extends ITreeResult<T>, R extends ITreeResult<R>> List<R> map(Collection<T> tree, BiFunction<T, T, R> converter, T parent) {
        if (tree == null) {
            return null;
        }
        List<R> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            R data = converter.apply(t, parent);
            data.setChildren(
                    map(t.getChildren(), converter, t)
            );
            result.add(data);
        }
        return result;
    }

    /**
     * 转换
     * @param tree 树形数据
     * @param converter 转换函数
     * @param <T>
     * @param <R>
     * @return
     */
    static <T extends ITreeResult<T>, R extends ITreeResult<R>> List<R> map(Collection<T> tree, Function<T, R> converter) {
        if (tree == null) {
            return null;
        }
        List<R> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            R data = converter.apply(t);
            data.setChildren(
                    map(t.getChildren(), converter)
            );
            result.add(data);
        }
        return result;
    }

    /**
     * 筛选（从叶子节点开始，先子后父）
     * @param tree 树形数据
     * @param predicate 过滤条件
     * @param parent 父数据
     * @param <T>
     * @param <R>
     * @return
     */
    static <T extends ITreeResult<T>>List<T> filter(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        if (tree == null) {
            return null;
        }
        List<T> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            t.setChildren(filter(t.getChildren(), predicate, t));
            if (predicate.test(t, parent)) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     * 筛选（从叶子节点开始，先子后父）
     * @param tree 树形数据
     * @param predicate 过滤条件
     * @param <T>
     * @return
     */
    static <T extends ITreeResult<T>>List<T> filter(Collection<T> tree, Predicate<T> predicate) {
        if (tree == null) {
            return null;
        }
        List<T> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            t.setChildren(filter(t.getChildren(), predicate));
            if (predicate.test(t)) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     * 筛选（根节点开始，先父后子）
     * @param tree 树形数据
     * @param predicate 过滤条件
     * @param parent 父数据
     * @param <T>
     * @param <R>
     * @return
     */
    static <T extends ITreeResult<T>>List<T> filterByParent(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        if (tree == null) {
            return null;
        }
        List<T> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            if (predicate.test(t, parent)) {
                result.add(t);
                t.setChildren(filterByParent(t.getChildren(), predicate, t));
            }
        }
        return result;
    }

    /**
     * 筛选（根节点开始，先父后子）
     * @param tree 树形数据
     * @param predicate 过滤条件
     * @param <T>
     * @return
     */
    static <T extends ITreeResult<T>>List<T> filterByParent(Collection<T> tree, Predicate<T> predicate) {
        if (tree == null) {
            return null;
        }
        List<T> result = new ArrayList<>(tree.size());
        for (T t : tree) {
            if (predicate.test(t)) {
                result.add(t);
                t.setChildren(filterByParent(t.getChildren(), predicate));
            }
        }
        return result;
    }

    /**
     * 查找元素
     * @param tree 树形数据
     * @param predicate 条件函数
     * @param parent 父数据
     * @param <T>
     * @return
     */
    static <T extends ITreeResult<T>>T find(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        if (tree == null) {
            return null;
        }
        for (T t : tree) {
            if (predicate.test(t, parent)) {
                return t;
            }
            t = find(t.getChildren(), predicate, t);
            if (t != null) {
                return t;
            }
        }
        return null;
    }

    /**
     * 查找元素
     * @param tree 树形数据
     * @param predicate 条件函数
     * @param <T>
     * @return
     */
    static <T extends ITreeResult<T>>T find(Collection<T> tree, Predicate<T> predicate) {
        if (tree == null) {
            return null;
        }
        for (T t : tree) {
            if (predicate.test(t)) {
                return t;
            }
            t = find(t.getChildren(), predicate);
            if (t != null) {
                return t;
            }
        }
        return null;
    }


    /**
     * 查找元素链（从目标元素到根节点的路径，记得倒转）
     * @param tree 树形数据
     * @param predicate 条件函数
     * @param parent 父数据
     * @return
     * @param <T>
     */
    static <T extends ITreeResult<T>>List<T> findLinkR(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        if (tree != null) {
            for (T t : tree) {
                if (predicate.test(t, parent)) {
                    List<T> result = new ArrayList<>(tree.size());
                    result.add(t);
                    return result;
                }
                List<T> link = findLinkR(t.getChildren(), predicate, t);
                if (!link.isEmpty()) {
                    link.add(t);
                    return link;
                }
            }
        }
        return Collections.emptyList();
    }

    /**
     * 查找元素链（从目标元素到根节点的路径，记得倒转）
     * @param tree 树形数据
     * @param predicate 条件函数
     * @return
     * @param <T>
     */
    static <T extends ITreeResult<T>>List<T> findLinkR(Collection<T> tree, Predicate<T> predicate) {
        if (tree != null) {
            for (T t : tree) {
                if (predicate.test(t)) {
                    List<T> result = new ArrayList<>(tree.size());
                    result.add(t);
                    return result;
                }
                List<T> link = findLinkR(t.getChildren(), predicate);
                if (!link.isEmpty()) {
                    link.add(t);
                    return link;
                }
            }
        }
        return Collections.emptyList();
    }

    /**
     * 查找元素链（从根节点到目标元素的路径）
     * @param tree 树形数据
     * @param predicate 条件函数
     * @param parent 父数据
     * @return
     * @param <T>
     */
    static <T extends ITreeResult<T>>List<T> findLink(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        List<T> link = findLinkR(tree, predicate, parent);
        Collections.reverse(link);
        return link;
    }

    /**
     * 查找元素链（从根节点到目标元素的路径）
     * @param tree 树形数据
     * @param predicate 条件函数
     * @return
     * @param <T>
     */
    static <T extends ITreeResult<T>>List<T> findLink(Collection<T> tree, Predicate<T> predicate) {
        List<T> link = findLinkR(tree, predicate);
        Collections.reverse(link);
        return link;
    }

    /**
     * 搜索（符合条件的数据返回数据和数据上下级）
     * @param tree 数据
     * @param predicate 条件函数
     * @param parent 父数据
     * @return
     * @param <V>
     * @param <T>
     * @param <R>
     */
    static <T extends ITreeResult<T>>List<T> query(Collection<T> tree, BiPredicate<T, T> predicate, T parent) {
        List<T> res = new ArrayList<>();
        for (T t : tree) {
            if (predicate.test(t, parent)) {
                res.add(t);
                continue;
            }
            if (CollectionUtils.isEmpty(t.getChildren())) {
                continue;
            }
            List<T> children = query(t.getChildren(), predicate, t);
            if (children.isEmpty()) {
                continue;
            }
            t.setChildren(children);
            res.add(t);
        }
        return res;
    }

    /**
     * 搜索（符合条件的数据返回数据和数据上下级）
     * @param tree 数据
     * @param predicate 条件函数
     * @return
     * @param <V>
     * @param <T>
     * @param <R>
     */
    static <T extends ITreeResult<T>>List<T> query(Collection<T> tree, Predicate<T> predicate) {
        List<T> res = new ArrayList<>();
        for (T t : tree) {
            if (predicate.test(t)) {
                res.add(t);
                continue;
            }
            if (CollectionUtils.isEmpty(t.getChildren())) {
                continue;
            }
            List<T> children = query(t.getChildren(), predicate);
            if (children.isEmpty()) {
                continue;
            }
            t.setChildren(children);
            res.add(t);
        }
        return res;
    }

    /**
     * 排序
     * @param tree 树形数据
     * @param comparator 比较函数
     * @param <T>
     * @return
     */
    static <T extends ITreeResult<T>>void sort(List<T> tree, Comparator<? super T> comparator) {
        if (tree == null) {
            return;
        }
        tree.sort(comparator);
        for (T t : tree) {
            sort(t.getChildren(), comparator);
        }
    }

}
